<!DOCTYPE html>
<html lang="zh">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<title>数独</title>
	<script src="../javascript/tools.js" type="text/javascript" charset="utf-8"></script>
	<script src="../javascript/sudo.js" type="text/javascript" charset="utf-8"></script>
	<style type="text/css">
		p {
			display: inline-block;
		}

		.gamebody {
			width: 550px;
			height: 550px;
			margin-left: auto;
			margin-right: auto;
			margin-top: 10px;
			font-size: 0;
			background-color: grey;
			border-radius: 10px;
		}

		.gameBorder {
			border-radius: 4px;
			background-color: aliceblue;
			width: calc(94% / 3);
			height: calc(94% / 3);
			display: inline-block;
			margin: 1%;
		}

		.gameBlock {
			width: calc(94% / 3);
			height: calc(94% / 3);
			background-color: silver;
			/* display: inline-block; */
			margin: 1%;
			border-radius: 4px;
			text-align: center;
			color: azure;
			float: left;
		}

		.wrong {
			color: red !important;
		}

		.warn {
			color: rgb(119, 78, 24) !important;
		}

		.winBlock {
			color: #696969;
		}

		.input {
			color: blue;
		}
	</style>

	<style type="text/css">
		.head,
		.row {
			width: 550px;
			margin: auto;
			margin-top: 20px;
		}

		.head:after {
			height: 0;
			display: block;
			content: '';
			clear: both;
		}

		button {
			height: 40px;
			float: left;
			margin-right: 5px;
			background-color: bisque;
			border: none;
			border-radius: 3px;
			font-size: 20px;
			line-height: 40px;
			color: darkorange;
		}

		button:active {
			background-color: darkorange;
			color: bisque;
		}

		.btn {
			margin: 0;
			float: right;
			width: 40px;
			height: 40px;
			background-color: grey;
			box-shadow: none;
			border: none;
			border-radius: 3px;
			color: beige;
			font-size: 20px;
			line-height: 40px;
		}

		.btn:hover {
			background-color: blue;
		}

		.btn:active {
			background-color: cadetblue;
		}

		#difficulty:before {
			content: 'difficulty : ';
			color: dimgray;
		}

		#difficulty {
			padding-left: 5px;
			padding-right: 5px;

			margin: 0;
			float: right;
			height: 40px;
			line-height: 40px;
			background-color: #5F9EA0;
		}
	</style>
</head>

<body oncontextmenu="return false;" onselectstart="return false">
	<div class="container">
		<div class="head">
			<button type="button" class="btn" id="add">+</button>
			<p id="difficulty">5</p><button type="button" class="btn" id="minus">-</button>
			<button type="button" id="Restart">Restart</button><button type="button" id="StartNew">StartNew</button>
			<button type="button" id="Save">Save</button>
			<!-- <button type="button" id="History">History</button> -->
		</div>
		<div class="row">
			<small>点击空白处选择数字，每个数字在横竖和自己的方格内只能有一个</small>
		</div>
		<div class="gamebody">
		</div>
	</div>
</body>
<script type="text/javascript">
	$get("#StartNew").onclick = function () {
		for (let i = 0; i < 9; i++) {
			for (let k = 0; k < 9; k++) {
				littleBlocks[i][k].innerText = '';
				littleBlocks[i][k].onclick = function () { };
				littleBlocks[i][k].style.cursor = "auto";

				littleBlocks[i][k].className = "gameBlock";
			}
		}
		sudo = getRandomSudo();
		printSudo();
		save();
		history++;
	}

	$get("#Restart").onclick = function () {
		for (let i = 0; i < 9; i++) {
			for (let k = 0; k < 9; k++) {
				if (littleBlocks[i][k].className.match('input')) {
					littleBlocks[i][k].className = 'gameBlock input';
				} else {
					littleBlocks[i][k].className = 'gameBlock';
				}
			}
		}
		for (let i = 0; i < 9; i++) {
			for (let k = 0; k < 9; k++) {
				littleBlocks[i][k].innerText = backupSudo[i][k];
			}
		}
		save();
	}

	$get("#add").onclick = function () {
		let num = new Number($get('#difficulty').innerText) + 1;
		if (num > 9) {
			return;
		}
		$get('#difficulty').innerText = num;
		hidingNumbers = 60 * num / 9;
	}

	$get("#minus").onclick = function () {
		let num = new Number($get('#difficulty').innerText) - 1;
		if (num < 1) {
			return;
		}
		$get('#difficulty').innerText = num;
		hidingNumbers = 60 * num / 9;
	}

	$get("#Save").onclick = function () {
		save();
	};


	function save() {

		if (history == -1) {
			history = 0;
		}
		let backup = new Array();
		for (let i = 0; i < 9; i++) {
			backup[i] = new Array();
			for (let k = 0; k < 9; k++) {
				backup[i][k] = {};
				backup[i][k].className = littleBlocks[i][k].className;
				backup[i][k].innerText = littleBlocks[i][k].innerText;
			}
		}
		console.log(history)
		localStorage.setItem('sudo' + history, JSON.stringify(backup));

	}
	function load() {
		let backup;
		while (1) {
			history++;
			backup = localStorage.getItem('sudo' + history);
			if (backup == undefined) {
				history--;
				break;
			}
		}
		if (history <= -1) {
			history = -1;
			return 0;
		}
		backup = localStorage.getItem('sudo' + history);
		backup = JSON.parse(backup);
		console.log(history)
		for (let i = 0; i < 9; i++) {
			for (let k = 0; k < 9; k++) {
				littleBlocks[i][k].className = backup[i][k].className;
				littleBlocks[i][k].innerText = backup[i][k].innerText;
				if (littleBlocks[i][k].className.match('input')) {
					littleBlocks[i][k].onclick = numOnclick;
					littleBlocks[i][k].style.cursor = "pointer";
				}
			}
		}
		return 1;

	}
	function clearSave() {
		history = 0;
		let backup;
		while (1) {
			backup = localStorage.getItem('sudo' + history);
			if (backup != undefined) {
				localStorage.removeItem('sudo' + history);
				history++
			} else {
				break;
			}
		}
		history = -1;
	}
	window.onkeydown = e => {
		if (e.key == 's') {
			save(e);
		} else if (e.key == 'l') {
			load();
		} else if (e.key == 'p') {
			clearSave();
		}
	}
</script>
<script type="text/javascript">
	let hidingNumbers = 60 * 5 / 9;
	let history = -1;
	for (let i = 0; i < 9; i++) { //生成界面
		$get('.gamebody')[0].innerHTML += '<div class="gameBorder"></div>';
		for (let k = 0; k < 9; k++) {
			$get('.gameBorder')[i].innerHTML += '<div class="gameBlock"></div>';
		}
	}
	let insetBlocks = function () { //分组保存方块
		let arr = new Array();
		for (let i = 0; i < 9; i++) {
			arr.push($get('.gameBorder')[i].$get(".gameBlock"));
		}
		return arr;
	}();
	let littleBlocks = function () { //保存最小单位的方块
		let blocks = $get('.gameBlock');
		let arr = new Array();
		for (let i = 0; i < 9; i++) {
			arr.push(new Array());
		}
		for (let i = 0; i < 3; i++) {
			for (let k = 0; k < 3; k++) {
				for (let x = 0; x < 3; x++) {
					for (let y = 0; y < 3; y++) {
						arr[i * 3 + x][k * 3 + y] = insetBlocks[i * 3 + k][x * 3 + y];
						arr[i * 3 + x][k * 3 + y].style.lineHeight = arr[i * 3 + x][k * 3 + y].offsetHeight + "px";
						arr[i * 3 + x][k * 3 + y].style.fontSize = arr[i * 3 + x][k * 3 + y].offsetHeight * 0.7 + "px";
					}
				}
			}
		}
		return arr;

	}();
	let sudo;
	let backupSudo = new Array();

	if (load()) {
	} else {
		sudo = getRandomSudo();
		printSudo();
	}

	function printSudo() { //输出数独到界面,随机隐藏部分数值
		let hidings = hidingNumbers;
		let flag = 0;
		for (let i = 0; i < 9; i++) {
			backupSudo[i] = new Array();
			for (let k = 0; k < 9; k++) {
				flag = Math.round(Math.random() * 81);
				if (hidings == 0) {
					backupSudo[i][k] = sudo[i][k]
					littleBlocks[i][k].innerText = sudo[i][k];
				} else if (flag < hidingNumbers) { //可输入数字区
					backupSudo[i][k] = '';
					hidings--;
					littleBlocks[i][k].innerText = '';
					littleBlocks[i][k].onclick = numOnclick;
					littleBlocks[i][k].style.cursor = "pointer";
					littleBlocks[i][k].className += " input";
				} else {
					backupSudo[i][k] = sudo[i][k]
					littleBlocks[i][k].innerText = sudo[i][k];
				}
			}
		}
	}

	function numOnclick() { //可输入部分单击事件

		let num = 1;
		if (this.innerText != undefined) {
			num = new Number(this.innerText);
			num++;
		}
		if (num > 9) {
			num = 1;
		}
		this.innerText = num;
		testSudo();
	}

	function testSudo() { //检测界面上的数独合法性
		for (let i = 0; i < 9; i++) {
			for (let k = 0; k < 9; k++) {
				if (littleBlocks[i][k].className.match('input')) {
					littleBlocks[i][k].className = 'gameBlock input';
				} else {
					littleBlocks[i][k].className = 'gameBlock';
				}
			}
		}
		let flag = 0;
		for (let i = 0; i < 9; i++) {

			for (let k = 0; k < 9; k++) {
				//横向纵向对比
				for (let x = 0; x < 9; x++) {
					if (littleBlocks[i][k].innerText == '') {
						flag = 1;
					}
					if (x != k && littleBlocks[i][k].innerText != '' && littleBlocks[i][k].innerText == littleBlocks[i][x].innerText) {
						if (littleBlocks[i][k].className.match("input")) {
							littleBlocks[i][k].className += ' wrong';
						} else {
							littleBlocks[i][k].className += ' warn';
						}
						if (littleBlocks[i][x].className.match("input")) {
							littleBlocks[i][x].className += ' wrong';
						} else {
							littleBlocks[i][x].className += ' warn';
						}
						flag = 1;
					}
					if (x != i && littleBlocks[i][k].innerText != '' && littleBlocks[i][k].innerText == littleBlocks[x][k].innerText) {
						if (littleBlocks[i][k].className.match("input")) {
							littleBlocks[i][k].className += ' wrong';
						} else {
							littleBlocks[i][k].className += ' warn';
						}
						if (littleBlocks[x][k].className.match("input")) {
							littleBlocks[x][k].className += ' wrong';
						} else {
							littleBlocks[x][k].className += ' warn';
						}
						flag = 1;

					}
				}
				let sx = k - k % 3;
				let sy = i - i % 3;
				for (let x = 0; x < 3; x++) {
					for (let y = 0; y < 3; y++) {
						if (y + sy != i && x + sx != k && littleBlocks[i][k].innerText != '' && littleBlocks[i][k].innerText == littleBlocks[y + sy][x + sx].innerText) {
							if (littleBlocks[i][k].className.match("input")) {
								littleBlocks[i][k].className += ' wrong';
							} else {
								littleBlocks[i][k].className += ' warn';
							}
							if (littleBlocks[y + sy][x + sx].className.match("input")) {
								littleBlocks[y + sy][x + sx].className += ' wrong';
							} else {
								littleBlocks[y + sy][x + sx].className += ' warn';
							}
							flag = 1;

						}
					}
				}
			}


		}
		if (flag == 0) {
			win();
		}

	}

	function win() {
		let x = 0;
		let y = 0;
		let flag = 0;
		let max = 8;
		let min = 0;
		for (let i = 0; i < 9; i++) {
			for (let k = 0; k < 9; k++) {
				littleBlocks[i][k].onclick = function () { };
			}
		}
		let wins = setInterval(() => {
			littleBlocks[y][x].className = 'gameBlock winBlock';

			if (max < min) {
				clearInterval(wins);
			}
			if (flag == 0) {
				x++;
				if (x >= max) {
					flag = 1;

				}
			} else if (flag == 1) {
				y++;
				if (y >= max) {
					flag = 2;
					max--;
				}
			} else if (flag == 2) {
				x--;
				if (x <= min) {
					flag = 3;
					min++;
				}
			} else if (flag == 3) {
				y--;
				if (y <= min) {
					flag = 0;

				}
			}
		}, 20)

	}


</script>

</html>